import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * 
 */

/**
 * @author varun
 *
 */
public class VendingMachineTest {
	private static final VendingMachineItem Chettos = null;
	private static final VendingMachineItem Pepsi = null;
	//Creating a new class vending machine
	public VendingMachine veMachine;
	//Creating a new item
    public VendingMachineItem veItem;
    public VendingMachineItem veItem1;
	private Object veItem3;

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		 veMachine = new VendingMachine();
         veItem= new VendingMachineItem("Chettos", 2.5);
         veItem1= new VendingMachineItem("Pepsi", 2.25);
	}

	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		 veMachine = null;
         veItem = null;
	}
	
		
	/**
	 * Test method for {@link VendingMachine#getItem(java.lang.String)}.
	 */
	//Checking whether the slot is empty
	@Test
	public void testAddItem() {
		 assertNull(veMachine.getItem(VendingMachine.B_CODE));
	}
		 //Adding an item in the slot
		@Test
			public void testAddItem_2(){
				veMachine.addItem(veItem, VendingMachine.B_CODE);
				  assertEquals(veItem, veMachine.getItem(VendingMachine.B_CODE));
		}
		//Check whether item is not in the wrong slot
		@Test
		public void testAddItem_4(){
         assertNull(veMachine.getItem(VendingMachine.A_CODE));
         assertNull(veMachine.getItem(VendingMachine.C_CODE));
         assertNull(veMachine.getItem(VendingMachine.D_CODE));
	}
	/**
	 *  Test add item for already occupied slot
	 *   @throws Exception VendingMachineException If trying to add item in a non-empty slot
	 */
	 @Test(expected = VendingMachineException.class)
	   public void testAddItem_5() throws Exception{
		 veMachine.addItem(veItem,"A");
		 veMachine.addItem(veItem1, "A");         
	        }
	    
	/**
     * If you add an item with an invalid code,then VendingMachineException will be thrown exception
     */
	   @Test (expected = VendingMachineException.class)
	    public void testAddItem_6() throws Exception{
	                    veMachine.addItem(Chettos,"E");
	        }
	   /**
        * Test add item for wrong item in the specified slot.
        * Test run will be false if the item's slot and the expected slot for the item are different.
        */
       @Test public void testAddItem_7() {
               veMachine.addItem(Chettos, VendingMachine.A_CODE);
               assertEquals(Pepsi,veMachine.getItem(veMachine.A_CODE));
       }

	/**
	 * Test method for {@link VendingMachine#removeItem(java.lang.String)}.
	 */
	@Test
	public void testRemoveItem() {
		veMachine.addItem(veItem, VendingMachine.B_CODE);
		//Checking whether the item is removed 
        VendingMachineItem removedItem = veMachine.removeItem(VendingMachine.B_CODE);
        //Checking whether the  correct item is removed  
        assertSame(veItem, removedItem);
        //Slot is empty from where the product is removed
         assertNull(veMachine.getItem(VendingMachine.B_CODE));
	}

	@Test (expected = VendingMachineException.class)
	public void testRemoveItem1() throws Exception {
	//	veMachine.addItem(veItem, VendingMachine.B_CODE);
		//Checking whether the item is removed 
        VendingMachineItem removedItem = veMachine.removeItem(VendingMachine.B_CODE);
        //Checking whether the  correct item is removed  
        assertSame(veItem, removedItem);
        //Slot is empty from where the product is removed
         assertNull(veMachine.getItem(VendingMachine.B_CODE));
	}	
	
	
	
	/**
	 * Test method for {@link VendingMachine#insertMoney(double)}.
	 */
	@Test
	public void testInsertMoney() {
		//Get current balance
        double balance = veMachine.balance;
        //Insert amount in machine
        veMachine.insertMoney(10);
        //new balance would be previous balance+New balance
        assertEquals(balance, veMachine.balance, 10.01);
     }

	
	@Test (expected = VendingMachineException.class)
	public void testInsertMoney1() throws Exception  {
		//Get current balance
        double balance = veMachine.balance;
        //Insert amount in machine
        veMachine.insertMoney(-10);
        //new balance would be previous balance+New balance
        assertEquals(balance, veMachine.balance, 10.01);
     }	

	/**
	 * Test method for {@link VendingMachine#getBalance()}.
	 */
	@Test
	public void testGetBalance() {
		 //Vending machine should have 0 balance
        assertEquals(0, veMachine.getBalance(), 0.1);
         //Balance should be>0   
        veMachine.insertMoney(60.1);
        double balance = veMachine.balance;
        //vending machine should return the amount of balance
        assertEquals(balance, veMachine.getBalance(), 1);
        assertEquals(balance, veMachine.balance, 1);
	}

	/**
	 * Test method for {@link VendingMachine#makePurchase(java.lang.String)}.
	 */
	@Test
	public void testMakePurchase() {
		 veMachine.addItem(veItem, VendingMachine.B_CODE);

         //Code to test if there is sufficient money to purchase
         assertFalse(veMachine.makePurchase(VendingMachine.B_CODE));

         //Code to test if money is equal to item.price
         veMachine.insertMoney(veItem.getPrice());
         //Should Returns true if there is Sufficient money to make the purchase
         assertTrue(veMachine.makePurchase(VendingMachine.B_CODE));
         //Code to test if the amount of the item is subtracted from the balance
         assertEquals(0, veMachine.balance, 60.01);
         //Code to test if the item is removed form vending machine
         assertNull(veMachine.getItem(VendingMachine.B_CODE));

         //Code to test if money > item.price
         veMachine.addItem(veItem, VendingMachine.A_CODE);
         veMachine.insertMoney(veItem.getPrice()+2.0);
         // Should Returns true if there is enough money to make the purchase
         assertTrue(veMachine.makePurchase(VendingMachine.A_CODE));
         //The amount of the item's purchase is subtracted from the balance
         assertEquals(2.0, veMachine.balance, 60.01);
         //the item has been removed
         assertNull(veMachine.getItem(VendingMachine.A_CODE));


         //test if the slot is empty
         assertFalse(veMachine.makePurchase(VendingMachine.A_CODE));

        
	}
	/**
	 * Test method for {@link VendingMachine#returnChange()}.
	 */
	@Test
	public void testReturnChange() {
		//when balance is 0
        assertEquals(0, veMachine.returnChange(), 10.01);
      //test when balance > 0
        veMachine.addItem(veItem, VendingMachine.A_CODE);
        veMachine.insertMoney(10);
        veMachine.makePurchase(VendingMachine.A_CODE);
      //Returns: The amount of change in the machine
        assertEquals(10-veItem.getPrice(), veMachine.returnChange(), 10.01);
      //when balance=0
        assertEquals(0, veMachine.balance, 10.01);
	}

	   @Test
       public void testAddItem_case() {
               
               
			//Add two items (Chettos and Pepsi) to the same slot in the vending machine.
               veMachine.addItem(Chettos, veMachine.A_CODE);
               veMachine.addItem(Pepsi , veMachine.A_CODE);
       }
	   /**
        *Checks whether the item exists, that is, whether it is in the vending machine 
        *before getting its price
        */
       @Test
       public void testGetPrice() {
               
               /**This item does not exist, that is, it is not initialized (no name or price)*/
       assertNull(veItem3);
       }
       

}

